package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/protos/peer"
	"strconv"
	"time"
)

type SimpleChainnode struct {
	Name   string `json:"name"`
	Gender string `json:"gender"`
}

func main() {

	err := shim.Start(new(SimpleChainnode))
	if err != nil {
		fmt.Printf("StartSimpleChaincode Error when start up : %s", err)
	}
}

func (t *SimpleChainnode) Init(stub shim.ChaincodeStubInterface) peer.Response {
	args := stub.GetStringArgs()
	if len(args) != 2 {
		return shim.Error("init parm allow 2 paramete only")
	}
	err := stub.PutState(args[0], []byte(args[1]))
	if err != nil {
		return shim.Error("Error when save state")
	}
	return shim.Success(nil)
}

func (t *SimpleChainnode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

	fun, args := stub.GetFunctionAndParameters()
	var result string
	var err error
	if fun == "set" {
		result, err = set(stub, args)
	} else if fun == "gethistory" {
		result, err = getHistoryForShow(stub, args)
	} else if fun == "setjsondata" {
		result, err = setjsondata(stub, args)
	} else if fun == "deletebykey" {
		result, err = deleteByKey(stub, args)
	} else {
		result, err = get(stub, args)
	}

	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(result))
}

func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 3 {
		return "", fmt.Errorf("Error Parameter num")
	}

	fmt.Println("ready store by key is   " + args[1])
	fmt.Println("ready store value is " + args[2])
	err := stub.PutState(args[1], []byte(args[2]))
	if err != nil {
		return "", fmt.Errorf(err.Error())
	}
	return string("success by " + args[1]), nil
}

func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {

	if len(args) != 1 {
		return "", fmt.Errorf("Error parameter num ")
	}
	fmt.Println("ready get data by" + args[0])

	result, err := stub.GetState(args[0])
	if err != nil {
		return "", fmt.Errorf("get data error")
	}
	if result == nil {
		return "", fmt.Errorf("According %s can't get data", args[0])
	}
	return string(result), nil
}

func deleteByKey(stub shim.ChaincodeStubInterface, args []string) (string, error) {

	var errfordel error
	if len(args) != 1 {
		return "errorparm", fmt.Errorf("Error Parameter num")
	}

	errfordel = stub.DelState(args[0])

	if errfordel != nil {
		return "", fmt.Errorf("deleteError")
	}

	return string("success delete key " + args[0]), nil

}



func getHistoryForShow(stub shim.ChaincodeStubInterface, args []string) (string, error) {

	if len(args) < 1 {
		return "errorforparm", fmt.Errorf("Incorrect number of arguments. Expecting 1")
	}

	keytemp := args[0]

	fmt.Printf("- start getHistoryForShow: %s\n", keytemp)

	resultsIterator, err := stub.GetHistoryForKey(keytemp)
	if err != nil {
		//return shim.Error(err.Error())
		return "errorForCallGethistory", err
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing historic values for the marble
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		response, err := resultsIterator.Next()
		if err != nil {
			return "errorfornext", err
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"TxId\":")
		buffer.WriteString("\"")
		buffer.WriteString(response.TxId)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Value\":")
		// if it was a delete operation on given key, then we need to set the
		//corresponding value null. Else, we will write the response.Value
		//as-is (as the Value itself a JSON marble)
		if response.IsDelete {
			buffer.WriteString("null")
		} else {
			buffer.WriteString(string(response.Value))
		}

		buffer.WriteString(", \"Timestamp\":")
		buffer.WriteString("\"")
		buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
		buffer.WriteString("\"")

	/*	buffer.WriteString(", \"IsDelete\":")
		buffer.WriteString("\"")
		buffer.WriteString(strconv.FormatBool(response.IsDelete))
		buffer.WriteString("\"")*/

		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	fmt.Printf("- getHistoryForMarble returning:\n%s\n", buffer.String())

	//return shim.Success(buffer.Bytes())
	return buffer.String(), nil
}

func setjsondata(stub shim.ChaincodeStubInterface, args []string) (string, error) {
	if len(args) != 3 {
		return "", fmt.Errorf("Error Parameter num")
	}
	var s SimpleChainnode
	s.Name = args[1]
	s.Gender = args[2]
	var jr []byte
	var errj error
	jr, errj = json.Marshal(s)
	if errj != nil {
		return "error", errj
	}
	err := stub.PutState(args[0], jr)
	if err != nil {
		return "", fmt.Errorf(err.Error())
	}
	return string("success by " + args[0]), nil
}
